package com.hm.base.auto;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.task.TaskExecutor;
import org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.hm.base.service.AuthorizationService;
import com.hm.base.service.RoleService;
import com.hm.base.service.SubscriberService;
import com.hm.base.service.SystemConfigDictService;
import com.hm.common.oss.qiniu.su.QiNiuHandlerSupport;
import com.hm.common.util.EncryptUtil;
import com.hm.core.ApiAspectSuport;

import lombok.extern.slf4j.Slf4j;

/**
 * @author shishun.wang
 * @date 下午12:02:11 2017年5月26日
 * @version 1.0
 * @param <T>
 * @describe
 */
@Slf4j
@EnableAsync // 配置 @Async 异步生效
@Configuration
@EnableConfigurationProperties({ SystemEnvConfigProperties.class })
@MapperScan("com.hm.base.mapper")
public class HmServerConfiguration<T> {

	@Autowired
	private SystemEnvConfigProperties systemEnvConfigProperties;

	@Value("${druid.url}")
	private String dbUrl;

	@Value("${druid.username}")
	private String username;

	@Value("${druid.password}")
	private String password;

	@Value("${druid.driver-class-name}")
	private String driverClassName;

	@Value("${druid.initialSize}")
	private int initialSize;

	@Value("${druid.minIdle}")
	private int minIdle;

	@Value("${druid.maxActive}")
	private int maxActive;

	@Value("${druid.maxWait}")
	private int maxWait;

	@Value("${druid.timeBetweenEvictionRunsMillis}")
	private int timeBetweenEvictionRunsMillis;

	@Value("${druid.minEvictableIdleTimeMillis}")
	private int minEvictableIdleTimeMillis;

	@Value("${druid.validationQuery}")
	private String validationQuery;

	@Value("${druid.testWhileIdle}")
	private boolean testWhileIdle;

	@Value("${druid.testOnBorrow}")
	private boolean testOnBorrow;

	@Value("${druid.testOnReturn}")
	private boolean testOnReturn;

	@Value("${druid.poolPreparedStatements}")
	private boolean poolPreparedStatements;

	@Value("${druid.maxPoolPreparedStatementPerConnectionSize}")
	private int maxPoolPreparedStatementPerConnectionSize;

	@Value("${druid.filters}")
	private String filters;

	@Value("${druid.connectionProperties}")
	private String connectionProperties;

	@Value("${druid.maxOpenPreparedStatements}")
	private int maxOpenPreparedStatements;

	@Autowired
	private BeanFactory beanFactory;

	@Bean
	@Primary // Spring优先选择被该注解所标记的数据源
	public DataSource dataSource() {
		DruidDataSource datasource = new DruidDataSource();

		datasource.setUrl(this.dbUrl);
		datasource.setUsername(EncryptUtil.AES.decrypt(username));
		datasource.setPassword(EncryptUtil.AES.decrypt(password));
		datasource.setDriverClassName(driverClassName);

		datasource.setInitialSize(initialSize);
		datasource.setMinIdle(minIdle);
		datasource.setMaxActive(maxActive);
		datasource.setMaxWait(maxWait);
		datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
		datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
		datasource.setValidationQuery(validationQuery);
		datasource.setTestWhileIdle(testWhileIdle);
		datasource.setTestOnBorrow(testOnBorrow);
		datasource.setTestOnReturn(testOnReturn);
		datasource.setPoolPreparedStatements(poolPreparedStatements);
		datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
		datasource.setConnectionProperties(connectionProperties);
		datasource.setMaxOpenPreparedStatements(maxOpenPreparedStatements);

		try {
			datasource.setFilters(filters);
		} catch (SQLException e) {
			log.error("druid configuration initialization filter", e);
		}
		datasource.setConnectionProperties(connectionProperties);

		return datasource;
	}

	@Bean(name = "sqlSessionFactory")
	public SqlSessionFactory sqlSessionFactoryBean() {
		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
		bean.setDataSource(dataSource());
		bean.setTypeAliasesPackage("com.hm.base.domain");// 每一张表对应的实体类

		// 添加XML目录
		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		try {
			bean.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/com/hm/base/mapper/*.xml"));// 每张表对应的xml文件
			return bean.getObject();
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	@Bean
	public ServletRegistrationBean druidServlet() {
		ServletRegistrationBean registration = new ServletRegistrationBean();
		registration.setServlet(new StatViewServlet());
		registration.addUrlMappings("/druid/*");
		// registration.addInitParameter("allow", "127.0.0.1"); //白名单
		// registration.addInitParameter("deny",""); //黑名单
		registration.addInitParameter("loginUsername", EncryptUtil.AES.decrypt(systemEnvConfigProperties.getDbBusWebUsername()));
		registration.addInitParameter("loginPassword", EncryptUtil.AES.decrypt(systemEnvConfigProperties.getDbBusWebPassword()));
		return registration;
	}

	@Bean
	public FilterRegistrationBean filterRegistrationBean() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
		filterRegistrationBean.setFilter(new WebStatFilter());
		filterRegistrationBean.addUrlPatterns("/*");
		filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
		return filterRegistrationBean;
	}

	@Bean
	public TaskExecutor taskExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(5);
		executor.setKeepAliveSeconds(300);
		executor.setMaxPoolSize(10);
		executor.setQueueCapacity(25);
		return executor;
	}

	@Bean
	public ApiAspectSuport apiAspectSuport() {
		return new ApiAspectSuport();
	}

	@Bean
	public QiNiuHandlerSupport qiNiuHandlerSupport() {
		return new QiNiuHandlerSupport(EncryptUtil.AES.decrypt(systemEnvConfigProperties.getQiniu().getAccessKey()), EncryptUtil.AES.decrypt(systemEnvConfigProperties.getQiniu().getSecretKey()), EncryptUtil.AES.decrypt(systemEnvConfigProperties.getQiniu().getBucket()))
				.setPrefixUri(EncryptUtil.AES.decrypt(systemEnvConfigProperties.getQiniu().getPrefixUri()));
	}

	/**** provide rpc invoker interface *******/

	@Bean(name = AuthorizationService.HTTP_INVOKER_EXPORT_CONTEXT)
	public HttpInvokerServiceExporter authorizationService() {
		HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
		httpInvokerServiceExporter.setServiceInterface(AuthorizationService.class);
		httpInvokerServiceExporter.setService(beanFactory.getBean(AuthorizationService.class));
		httpInvokerServiceExporter.afterPropertiesSet();
		return httpInvokerServiceExporter;
	}

	@Bean(name = RoleService.HTTP_INVOKER_EXPORT_CONTEXT)
	public HttpInvokerServiceExporter roleService() {
		HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
		httpInvokerServiceExporter.setServiceInterface(RoleService.class);
		httpInvokerServiceExporter.setService(beanFactory.getBean(RoleService.class));
		httpInvokerServiceExporter.afterPropertiesSet();
		return httpInvokerServiceExporter;
	}

	@Bean(name = SubscriberService.HTTP_INVOKER_EXPORT_CONTEXT)
	public HttpInvokerServiceExporter subscriberService() {
		HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
		httpInvokerServiceExporter.setServiceInterface(SubscriberService.class);
		httpInvokerServiceExporter.setService(beanFactory.getBean(SubscriberService.class));
		httpInvokerServiceExporter.afterPropertiesSet();
		return httpInvokerServiceExporter;
	}

	@Bean(name = SystemConfigDictService.HTTP_INVOKER_EXPORT_CONTEXT)
	public HttpInvokerServiceExporter systemConfigDictService() {
		HttpInvokerServiceExporter httpInvokerServiceExporter = new HttpInvokerServiceExporter();
		httpInvokerServiceExporter.setServiceInterface(SystemConfigDictService.class);
		httpInvokerServiceExporter.setService(beanFactory.getBean(SystemConfigDictService.class));
		httpInvokerServiceExporter.afterPropertiesSet();
		return httpInvokerServiceExporter;
	}

}
